<?php

namespace SwoPhp\Route;

class Route
{
    protected static $instance = null;

    protected $routeMap = [];

    protected $routes = [];

    protected $method = null;

    protected $flag = null;

    public function __construct()
    {
        $this->routeMap = [
            'Http' => app()->getBasePath() . '/route/http.php',
            'WebSocket' => app()->getBasePath() . '/route/web_socket.php',
        ];
    }

    public static function getInstance()
    {
        if (is_null(static::$instance)) {
            static::$instance = new static();
        }
        return static::$instance;
    }

    public function registerRoute()
    {
        foreach ($this->routeMap as $key => $path) {
            $this->flag = $key;
            require_once $path;
        }
        return $this;
    }

    public function match($path,$param = [])
    {
        foreach ($this->routes[$this->flag][$this->method] as $uri => $value) {
            if ($path === $uri) {
                $action = $value;
                break;
            }
        }

        if (!empty($action)) {
            $namespace = "\App\\".$this->flag."\Controller\\";
            $arr = \explode("@", $action);
            $controller = $namespace.$arr[0];
            $class = new $controller();
            return $class->{$arr[1]}(...$param);
        }

        return '404';
    }

    public function get($uri, $action)
    {
        $this->addRoute(['GET'], $uri, $action);
    }

    public function post($uri, $action)
    {
        $this->addRoute(['POST'], $uri, $action);
    }

    public function ws($uri, $controller)
    {
        $this->addRoute(['open'], $uri, $controller.'@open');
        $this->addRoute(['message'], $uri, $controller.'@message');
        $this->addRoute(['close'], $uri, $controller.'@onclose');
    }

    protected function addRoute($methods, $uri, $action)
    {
        foreach ($methods as $method) {
            $this->routes[$this->flag][$method][$uri] = $action;
        }
        return $this;
    }

    public function setMethod($method)
    {
        $this->method = $method;
        return $this;
    }

    public function setFlag($flag)
    {
        $this->flag = $flag;
        return $this;
    }

}
